package com.bungarus.test;

import com.bungarus.codec.protobuf.MessageProtobuf;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.FutureTask;
import java.util.function.Consumer;

/**
 * Test case for message from one client
 */
public class AccessTestClient extends AbstractAccessTestClient{

    public static void main(String[] args) throws Exception {
        new AccessTestClient().run(System.getProperty("access"));
    }

    /**
     * Test for login and IM message
     * type "login" in command line to login and get session id, and type other string to send IM message
     * type "logout" in command line to logout
     * asume that the current user data is {"accountName":"username","password":"password1","tenantId":"10000","id":1001}
     * asume the current user send message to himself, so you will receive message sent by yourself
     */
    protected void run(String accessPoint)  {
        connectServer(accessPoint);
        while (true){
            String line = getInputString();
            MessageProtobuf.Message message;
            if(line.equalsIgnoreCase("login")) { //login
                message = TestClientMessageBuilder.buildLoginMessage(
                        "abc123",
                        "1001",
                        10000,
                        "Apo",
                        "Device",
                        "username",
                        "password1"
                );
                send(message);
            }
            else if(line.equalsIgnoreCase("logout")) { // logout
                message = TestClientMessageBuilder.buildLogoutMessage(
                        loggedInUser,
                        "Apo",
                        "Device"
                );
                send(message);
            }
            else if(line.equalsIgnoreCase("no_session_id")) {
                message = TestClientMessageBuilder.buildNoSessionIdMessage(
                        loggedInUser,
                        "1002",
                        "Apo",
                        "Device",
                        line
                );
                send(message);
            }
            else if(line.startsWith("concurrent ")) {
                int concurrentClients = Integer.parseInt(line.substring("concurrent ".length()));
                doPerformanceTest(concurrentClients, 500, index -> {
                    MessageProtobuf.Message msg = TestClientMessageBuilder.buildIMMessage(
                            String.valueOf(System.currentTimeMillis()),
                            loggedInUser,
                            "1002",
                            "Apo",
                            "Device",
                            Thread.currentThread().getName() + "'s concurrent message " + index);
                    send(msg);
                });
            }
            else { // IM message
                int from = Integer.parseInt(System.getProperty("from", "0"));
                int to = Integer.parseInt(System.getProperty("to", "1"));
                for (int i = from; i < to; i++) {
                    message = TestClientMessageBuilder.buildIMMessage(
                            String.valueOf(System.currentTimeMillis()),
                            loggedInUser,
                            "1002",
                            "Apo",
                            "Device",
                            line + i
                    );
                    // sending
                    send(message);
                    try {
                        Thread.sleep(0);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    private void doPerformanceTest(final int nThread, final int exeCount, final Consumer<Integer> task) {
        CountDownLatch startLatch = new CountDownLatch(1);
        CountDownLatch endLatch = new CountDownLatch(nThread);

        for(int i=0; i<nThread; i++) {
            new Thread(() -> {
                try {
                    startLatch.await();
                    for(int j=0; j<exeCount; j++) {
                        task.accept(j);
                        Thread.sleep(0);
                    }
                    endLatch.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }

        startLatch.countDown();
        try {
            endLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
